#include "std.h"
#include "dumpstat.h"
#include "comm.h"
#include "file.h"

/*
 * Write statistics about objects on file.
 */

static int sumSizes(mapping_t *, mapping_node_t *, void *);
static int svalue_size(svalue_t *);

static int sumSizes(mapping_t * m, mapping_node_t * elt, void * tp)
{
	int *t = (int *) tp;

	*t += (svalue_size(&elt->values[0]) + svalue_size(&elt->values[1]));
	*t += sizeof(mapping_node_t);
	return 0;
}

int depth = 0;

static int svalue_size(svalue_t * v)
{
	int i, total;

	switch (v->type)
	{
		case T_OBJECT:
		case T_REAL:
		case T_NUMBER:
			return 0;
		case T_STRING:
			return (int) (strlen(v->u.string) + 1);
		case T_ARRAY:
		case T_CLASS:
			if (++depth > 100)
				return 0;

			/* first svalue is stored inside the array struct */
			total = sizeof(array_t) - sizeof(svalue_t);
			for (i = 0; i < v->u.arr->size; i++)
			{
				total += svalue_size(&v->u.arr->item[i]) + sizeof(svalue_t);
			}
			depth--;
			return total;
		case T_MAPPING:
			if (++depth > 100)
				return 0;
			total = sizeof(mapping_t);
			mapTraverse(v->u.map, sumSizes, &total);
			depth--;
			return total;
		case T_FUNCTION:
		{
			svalue_t tmp;
			tmp.type = T_ARRAY;
			tmp.u.arr = v->u.fp->hdr.args;

			if (++depth > 100)
				return 0;

			if (tmp.u.arr)
				total = (int) (sizeof(funptr_hdr_t) + svalue_size(&tmp));
			else
				total = (int) (sizeof(funptr_hdr_t));
			switch (v->u.fp->hdr.type)
			{
				case FP_EFUN:
					total += sizeof(efun_ptr_t);
					break;
				case FP_LOCAL | FP_NOT_BINDABLE:
					total += sizeof(local_ptr_t);
					break;
				case FP_SIMUL:
					total += sizeof(simul_ptr_t);
					break;
				case FP_FUNCTIONAL:
				case FP_FUNCTIONAL | FP_NOT_BINDABLE:
					total += sizeof(functional_t);
					break;
			}

			depth--;
			return total;
		}
#ifndef NO_BUFFER_TYPE
		case T_BUFFER:
			/* first byte is stored inside the buffer struct */
			return (int) (sizeof(buffer_t) + v->u.buf->size - 1);
#endif
		default:
			fatal("Illegal type: %d\n", v->type);
	}
	/* NOTREACHED */
	return 0;
}

int data_size(object_t * ob)
{
	int total = 0, i;

	if (ob->prog)
	{
		for (i = 0; i < (int) ob->prog->num_variables_total; i++)
		{
			depth = 0;
			total += svalue_size(&ob->variables[i]) + sizeof(svalue_t);
		}
	}
	return total;
}

void dumpstat(char * tfn)
{
	FILE *f;
	object_t *ob;
	char *fn;
#ifdef F_SET_HIDE
	int display_hidden;
#endif

	fn = check_valid_path(tfn, current_object, "dumpallobj", 1);
	if (!fn)
	{
		error("Invalid path '/%s' for writing.\n", tfn);
		return;
	}
	f = fopen(fn, "w");
	if (!f)
	{
		error("Unable to open '/%s' for writing.\n", fn);
		return;
	}

#ifdef F_SET_HIDE
	display_hidden = -1;
#endif
	for (ob = obj_list; ob; ob = ob->next_all)
	{
		int tmp;

#ifdef F_SET_HIDE
		if (ob->flags & O_HIDDEN)
		{
			if (display_hidden == -1)
				display_hidden = valid_hide(current_object);
			if (!display_hidden)
				continue;
		}
#endif
		/* FIXME */
		if (ob->prog && (ob->prog->ref == 1 || !(ob->flags & O_CLONE)))
			tmp = ob->prog->total_size;
		else
			tmp = 0;
		fprintf(f, "%-20s %i ref %2d %s %s (%d) %s\n", ob->name,
		        tmp + data_size(ob) + sizeof(object_t), ob->ref,
		        ob->flags & O_HEART_BEAT ? "HB" : "  ",
#ifndef NO_ENVIRONMENT
		        ob->super ? ob->super->name : "--",
#else
		        "--",
#endif
		        /* ob->cpu */0,
		        (ob->swap_num >= 0) ? ((ob->flags & O_SWAPPED) ?
				        "SWAPPED(out)" : "SWAPPED(in)") : "");
	        }
	fclose(f);
}
